#include "../../../common/etcd.hpp"
#include <gflags/gflags.h>
#include <thread>
#include <brpc/server.h>
#include <butil/logging.h>
#include "main.pb.h"

DEFINE_bool(run_mode, false, "程序的运行模式, false-调试; true-发布;");
DEFINE_string(log_file, "", "发布模式下, 用于指定日志的输出文件");
DEFINE_int32(log_level, 0, "发布模式下, 用于指定日志输出等级");

DEFINE_string(etcd_host, "http://127.0.0.1:2379", "服务注册中心地址");
DEFINE_string(base_service, "/service", "服务监控根目录");
DEFINE_string(instance_name, "/echo/instance", "当前实例名称");
DEFINE_string(access_host, "127.0.0.1:7070", "当前实例的外部访问地址"); // etcd注册时, 告诉这是提供服务地址
DEFINE_int32(listen_port, 7070, "Rpc服务器监听端口, 和上面的端口号一样");// 这是rpc服务器监听端口

//1. 继承与EchoService创建一个子类, 并实现rpc调用的业务功能
class EchoServiceImpl : public example::EchoService{     //EchoService类是远程调用rpc服务的类 - 就是真正进行sum计算的
    public:
    // 重写这个虚函数
    //RpcController: 返回结果是成功或失败   
    //request客户端的请求   response服务器要构造的响应
    //Closure: 服务端是异步执行的, 将Response的响应设置完了, 再调用run函数, 告诉服务器可以发给客户端响应了
    //这些参数时谁提供的? 调用Echo的参数提供的
    void Echo(google::protobuf::RpcController* controller, const ::example::EchoRequest* request,
              ::example::EchoResponse* response, ::google::protobuf::Closure* done)
    {
        //防止程序员忘记最后调用run函数, 所以用智能指针来管理起来
        brpc::ClosureGuard rpc_guard(done);
        std::cout << "收到消息:" << request->message() << std::endl;

        std::string str = request->message() + "--这是响应!!";
        response->set_message(str);
        // done->Run()      如果不写上面的guard, 则需要加上这句话
    }
};


int main(int argc, char* argv[])
{
    google::ParseCommandLineFlags(&argc, &argv, true);  //初始化命令行解析
    wufan_im::init_logger(FLAGS_run_mode, FLAGS_log_file, FLAGS_log_level);   // 初始化日志

    // 服务端改造思想: 
    // 关闭brpc的默认日志输出
    logging::LoggingSettings settings;
    settings.logging_dest = logging::LoggingDestination::LOG_TO_NONE;
    logging::InitLogging(settings);
    //2. 构造服务器对象
    brpc::Server server;
    
    //3. 向服务器对象中, 新增EchoService服务
    EchoServiceImpl echo_service;
    int ret = server.AddService(&echo_service, brpc::ServiceOwnership::SERVER_DOESNT_OWN_SERVICE);
    if (ret == -1){
        std::cout << "添加Rpc服务失败!\n";
        return -1;
    }
    //参数1: 添加服务, 只有你添加了服务, 服务器才能处理你对应的请求, 和路由很像    类型为Service*, EchoServiceImpl是它的子类
    //参数2: 添加服务失败的时候, 服务器是否会删除该对象  因为echo_service是局部变量, 所以不用去释放

    //4. 启动服务器
    brpc::ServerOptions options;    //启动服务器时的配置类
    options.idle_timeout_sec = -1;  //连接空闲超时时间 - 超时后连接被关闭
    options.num_threads = 1;        //io线程数量
    ret = server.Start(FLAGS_listen_port, &options);    //启动RPC服务
    if (ret == -1) {
        std::cout << "启动服务器失败! \n";
        return -1;
    } 
    //4. 注册服务
    auto rclient = std::make_shared<wufan_im::Registry>(FLAGS_etcd_host); //服务注册中心地址 - etcd服务已在linux里启动
    rclient->registry(FLAGS_base_service + FLAGS_instance_name, FLAGS_access_host); //要注册的服务 - 提供rpc服务的地址

    std::this_thread::sleep_for(std::chrono::seconds(600));
    return 0;
}